package categoryservice

import (
	"errors"
	"fmt"
	"time"
	"yunj/pkg/global"
	"yunj/pkg/yunj/core/builder"
	"yunj/pkg/yunj/core/builder/builderconsts"
	"yunj/pkg/yunj/core/builder/builderdto"
	"yunj/pkg/yunj/core/builder/builderenum"
	"yunj/pkg/yunj/core/builder/form"
	"yunj/pkg/yunj/core/builder/form/button"
	"yunj/pkg/yunj/core/builder/form/field"
	"yunj/pkg/yunj/core/builder/table"
	"yunj/pkg/yunj/core/builder/table/col"
	"yunj/pkg/yunj/core/builder/table/col/action"
	"yunj/pkg/yunj/core/builder/table/deftoolbar"
	"yunj/pkg/yunj/core/builder/table/toolbar"
	"yunj/pkg/yunj/util"

	"yunj/app/data"
	"yunj/app/dto"
	"yunj/app/model"
	"yunj/app/validator/client/categoryvalidator"
	"yunj/pkg/yunj/app/enum/stateenum"

	"github.com/gin-gonic/gin"
	"github.com/worklz/go-validate"
	"gorm.io/gorm"
)

type categoryPage struct {
}

var CategoryPage *categoryPage

// 树节点

func (s *categoryPage) TreeNodes(pid uint64, dbItems []*model.Category) (nodes []*dto.AdminCategoryPageTreeNode, err error) {
	nodes = []*dto.AdminCategoryPageTreeNode{}
	if dbItems == nil {
		err = global.MySQL.Where("state = ?", stateenum.NORMAL).Order("sort asc").Find(&dbItems).Error
		if err != nil {
			err = fmt.Errorf("获取所有正常分类数据异常！%v", err)
			return
		}
	}
	for _, item := range dbItems {
		if item.Pid == pid {
			node := &dto.AdminCategoryPageTreeNode{}
			node.Id = item.Id
			node.Name = item.Name
			node.Pid = item.Pid
			node.Img = item.Img
			nodes = append(nodes, node)
			var subNodes []*dto.AdminCategoryPageTreeNode
			subNodes, err = s.TreeNodes(item.Id, dbItems)
			if err != nil {
				return
			}
			if len(subNodes) > 0 {
				nodes = append(nodes, subNodes...)
			}
		}
	}
	return
}

// 回收站构建器
func (s *categoryPage) RecyleBinBuilder(ctx *gin.Context) *builder.Table {
	return builder.NewTable(ctx, "CategoryRecyleBinList").
		State([]builderdto.TableState{
			{Code: stateenum.RECYLE_BIN, Title: "回收站"},
		}).
		Page(false).
		Toolbar(func(t *builder.Table, state *builderdto.TableState) (actions []toolbar.ActionInterface, err error) {
			actions = []toolbar.ActionInterface{
				toolbar.NewAsyncEvent(builderenum.TABLE_EVENT_TYPE_NORMAL, "恢复正常").SetDropdown(true).SetAuth("yunj_category_normal"),
				toolbar.NewAsyncEvent(builderenum.TABLE_EVENT_TYPE_DELETED, "永久删除").SetDropdown(true).SetAuth("yunj_category_deleted"),
			}
			return
		}).
		DefaultToolbar([]deftoolbar.ActionInterface{
			deftoolbar.NewFilter(),
		}).
		Cols(func(t *builder.Table, state *builderdto.TableState) (cols []table.ColInterface, err error) {
			cols = []table.ColInterface{
				col.NewCheckbox("id", "ID"),
				col.NewText("name", "分类"),
				col.NewText("alias", "别名"),
				col.NewImage("img", "图片").SetAlign(builderconsts.ALIGN_CENTER),
			}
			actionCol := col.NewAction("操作").SetOptions([]action.ActionInterface{
				action.NewOpenPopup("edit", "详情").SetClass("layui-icon-survey").SetUrl(util.BuildAdminUrl("/category/edit")).SetAuth("yunj_category_edit"),
				action.NewAsyncEvent(builderenum.TABLE_EVENT_TYPE_NORMAL, "恢复正常").SetDropdown(true).SetAuth("yunj_category_normal"),
				action.NewAsyncEvent(builderenum.TABLE_EVENT_TYPE_DELETED, "永久删除").SetDropdown(true).SetAuth("yunj_category_deleted").SetConfirmFormFields(field.NewTxt("tips", "确认删除？")),
			})
			cols = append(cols, actionCol)
			return
		}).
		Validator(func(t *builder.Table) (validate.ValidatorInterface, error) {
			v := &categoryvalidator.Category{}
			v.InitValidator(v)
			return v, nil
		}).
		Count(func(t *builder.Table, requestParam *builderdto.TableRequestParam) (res builderdto.TableCountResult, err error) {
			// 状态数量查询
			query := global.MySQL.Model(&model.Category{})
			s.listBuilderFilterQuery(query, requestParam)
			err = query.Count(&res.Count).Error
			if err != nil {
				err = fmt.Errorf("数据量查询异常！%v", err)
				return
			}
			return
		}).
		Items(func(t *builder.Table, requestParam *builderdto.TableRequestParam) (res builderdto.TableItemsResult, err error) {
			query := global.MySQL.Select("*")
			s.listBuilderFilterQuery(query, requestParam)
			query.Order("last_update_time desc")
			var dbItems []*model.Category
			if err = query.Find(&dbItems).Error; err != nil {
				err = fmt.Errorf("数据查询异常！%v", err)
				return
			}
			res.Items, err = s.listBuilderItemsHandle(dbItems)
			return
		}).
		Event(func(t *builder.Table, requestParam *builderdto.TableRequestParam) (res builderdto.TableEventResult, err error) {
			handleEventRes, err := builderenum.HandleEvent(ctx, &model.Category{}, requestParam.EventCode, requestParam.Pks, func(param *builderenum.EventDbParam, e *builderenum.Event, pks []any) (err error) {
				if e.Value == builderenum.TABLE_EVENT_TYPE_DELETED {
					param.Data["alias"] = gorm.Expr("concat(`alias`, '_del_', ?)", time.Now().In(time.Local).Format("20060102150405"))
					param.Where = append(param.Where, []any{"alias <> ?", global.Config.Default.Category.Alias})
				} else if e.Value == builderenum.TABLE_EVENT_TYPE_RECYLE_BIN {
					param.Where = append(param.Where, []any{"alias <> ?", global.Config.Default.Category.Alias})
				}
				if _, exists := param.Data["updated_at"]; exists {
					param.Data["last_update_time"] = time.Now().In(time.Local).Unix()
					delete(param.Data, "updated_at")
				}
				return
			})
			if err != nil {
				return
			}
			if handleEventRes != nil {
				res.ResponseJsonData = handleEventRes
				return
			}
			err = fmt.Errorf("异常事件[%v]", requestParam.EventCode)
			return
		})
}

// 列表数据项处理
func (s *categoryPage) listBuilderItemsHandle(items []*model.Category) (resItems []*dto.AdminCategoryPageListItemResponse, err error) {
	if len(items) <= 0 {
		return
	}
	resItems = make([]*dto.AdminCategoryPageListItemResponse, 0, len(items))
	for _, item := range items {
		resItem := &dto.AdminCategoryPageListItemResponse{
			Id:    item.Id,
			Name:  item.Name,
			Alias: item.Alias,
			Img:   item.Img,
		}
		resItems = append(resItems, resItem)
	}
	return
}

// 列表过滤条件查询对象
func (s *categoryPage) listBuilderFilterQuery(query *gorm.DB, requestParam *builderdto.TableRequestParam) {
	// ids
	if len(requestParam.Pks) > 0 {
		query.Where("`id` in ?", requestParam.Pks)
	}
	// state
	query.Where("state = ?", stateenum.RECYLE_BIN)
}

// 编辑构建器
func (s *categoryPage) EditBuilder(ctx *gin.Context) (formBuilder *builder.Form) {
	formBuilder = builder.NewForm(ctx, "CategoryForm").
		Field(func(f *builder.Form, tab *builderdto.FormTab) (fields []form.FieldInterface, err error) {
			fields = []form.FieldInterface{
				field.NewHidden("id"),
				field.NewText("name", "名称").SetVerify("required|chsDash|max:100").SetDesc("只能输入汉字、字母、数字和下划线_及短横线-"),
				field.NewText("alias", "别名").SetVerify("required|alphaDash|max:80").SetDesc("只能输入字母/数字/下划线_及短横线-"),
				field.NewImage("img", "图片").SetVerify("url"),
				field.NewTextarea("desc", "描述").SetVerify("max:200").SetDesc("限制200字符数"),
				field.NewDatetime("create_time", "添加时间").SetReadonly(true),
				field.NewDatetime("last_update_time", "上次修改时间").SetReadonly(true),
			}
			// 设置栅格布局
			for _, v := range fields {
				v.SetFieldGrid([]any{12, 6, "6 l3 r3"})
			}
			return
		}).
		Button(func(f *builder.Form) (buttons []form.ButtonInterface, err error) {
			buttons = []form.ButtonInterface{
				button.NewReset(),
				button.NewSubmit(),
			}
			return
		}).
		Validator(func(f *builder.Form) (validate.ValidatorInterface, error) {
			v := &categoryvalidator.Category{}
			v.InitValidator(v)
			return v, nil
		}).
		Load(func(f *builder.Form) (res any, err error) {
			id := util.QueryUint64Param(ctx, "id")
			if id <= 0 {
				err = fmt.Errorf("异常数据")
				return
			}
			var data model.Category
			dbErr := global.MySQL.Where("`id` = ? and state <> ?", id, stateenum.DELETED).First(&data).Error
			if (dbErr != nil && !errors.Is(dbErr, gorm.ErrRecordNotFound)) || data.Id <= 0 {
				err = fmt.Errorf("数据获取异常！%v", dbErr)
				return
			}
			if data.Alias == global.Config.Default.Category.Alias {
				err = fmt.Errorf("默认分类不允许编辑！")
				return
			}
			res = dto.AdminCategoryPageFormLoadResponse{
				Id:             data.Id,
				Name:           data.Name,
				Alias:          data.Alias,
				Img:            data.Img,
				Desc:           data.Desc,
				CreateTime:     data.CreateTime,
				LastUpdateTime: data.LastUpdateTime,
			}
			return
		}).
		Submit(func(f *builder.Form, values map[string]any) (res builderdto.FormSubmitResult, err error) {
			var dbCategory *model.Category
			dbCategory = util.MapKeyValue(values, "dbCategory", dbCategory)
			err = global.MySQL.Where("alias <> ?", global.Config.Default.Category.Alias).Select("name", "alias", "img", "desc", "last_update_time").Save(dbCategory).Error
			if err != nil {
				err = fmt.Errorf("编辑失败！%v", err.Error())
				return
			}
			// 处理所有分类数据的完整属性值，并清理缓存
			err = data.HandleAllCategoryFullAttr()
			res.Reload = true
			return
		})
	return
}
